--[[Balance chasing functions for Stygian. 

--This function will take as its arguments
--Stygian_chaser(codeString, options)

--options are passed as a table and parsed as follows (use boolean objects true or false. All will default to true)

--needsEq:     Do you have to have equilibrium in order perform the action? 
--needsBal:    Do you have to have balance in order to perform the action?
--consumesEq:  Will it strip you of equilibrium to perform the action?
--consumesBal: Will it strip you of balance to perform the action?

--What this means is it will default to all true. You need both to do it, and lose both when you do. Which doesn't happen often, 
--but a side effect of this is that to create a trigger which requires both but only consumes balance, you could call ]]--

--Stygian_chaser([[stygian_cleanse()]], {consumesEq = false}) 

--[[Minus the -- of course. The codeString argument should be used like the code to execute portion of tempTimer. 
Now, this function should be called as part of an event. I'd put it in two events, actually. onBalanceRegained, and onEquilibriumRegained or similar. Have these events check if you're chasing eq/bal currently, and if so do nothing (in case you get a prompt in between doing something and sending what you're doing) otherwise, it'll run the Stygian_doChase() function to actually try chasing eq/bal. 
The execution order is thus:
First, if you have both balance and eq, it will execute all of the things which require both, but consume nothing. Then those which require eq, but consume nothing, then those which require bal, but consume nothing. Then it will check if you have anything which requires both and consumes both, and do that. Then its execution varies based on configuration. If you have it configured to check eq first, it will check for those things which require both but consume only eq, and execute that. If there is nothing which requires both but consumes only eq, it'll check for those which require both and consume only balance. It will then check for this which require only Eq and consume it, then those which require only balance and consume it. 
If you don't have both balance and equilibrium, it will only execute for the one you do have. 
]]
--initialize the tables of actions if they do not currently exist
Stygian = Stygian or {}
Stygian.config = Stygian.config or {}
if Stygian.config.ChaseEqFirst == nil then Stygian.config.ChaseEqFirst = true end
Stygian.balances = Stygian.balances or {}
Stygian.balances.balance = Stygian.balances.balance or 1
Stygian.balances.equilibrium = Stygian.balances.equilibrium or 1
Stygian.NeedsEqAndBal = Stygian.NeedsEqAndBal or {}
Stygian.NeedsEqAndBal.ConsumesEqAndBal = Stygian.NeedsEqAndBal.ConsumesEqAndBal or {}
Stygian.NeedsEqAndBal.ConsumesEq = Stygian.NeedsEqAndBal.ConsumesEq or {}
Stygian.NeedsEqAndBal.ConsumesBal = Stygian.NeedsEqAndBal.ConsumesBal or {}
Stygian.NeedsEqAndBal.ConsumesNeither = Stygian.NeedsEqAndBal.ConsumesNeither or {}
Stygian.NeedsEq = Stygian.NeedsEq or {}
Stygian.NeedsEq.ConsumesEq = Stygian.NeedsEq.ConsumesEq or {}
Stygian.NeedsEq.ConsumesNothing = Stygian.NeedsEq.ConsumesNothing or {}
Stygian.NeedsBal = Stygian.NeedsBal or {}
Stygian.NeedsBal.ConsumesBal = Stygian.NeedsBal.ConsumesBal or {}
Stygian.NeedsBal.ConsumesNothing = Stygian.NeedsBal.ConsumesNothing or {}
Stygian.chasingEq = Stygian.chasingEq or false
Stygian.chasingBal = Stygian.chasingBal or false
Stygian.currentlyChasingEq = Stygian.currentlyChasingEq or ""
Stygian.currentlyChasingBal = Stygian.currentlyChasingBal or ""

function Stygian_chaserReset()
  Stygian.NeedsEqAndBal = {}
  Stygian.NeedsEqAndBal.ConsumesEqAndBal = {}
  Stygian.NeedsEqAndBal.ConsumesEq = {}
  Stygian.NeedsEqAndBal.ConsumesBal = {}
  Stygian.NeedsEqAndBal.ConsumesNeither = {}
  Stygian.NeedsEq = {}
  Stygian.NeedsEq.ConsumesEq = {}
  Stygian.NeedsEq.ConsumesNothing = {}
  Stygian.NeedsBal = {}
  Stygian.NeedsBal.ConsumesBal = {}
  Stygian.NeedsBal.ConsumesNothing = {}
  Stygian.chasingEq = false
  Stygian.chasingBal = false
  Stygian.currentlyChasingEq = ""
  Stygian.currentlyChasingBal = ""
end

function Stygian_chaser(code, optiontable)
  SDebug("chaser", "Ok, we're adding a chaser object")
  if not code then --If they don't give us code to send, print some usage information
    cecho(align("You should at least tell us what to do.", {cap = "--=={{", capColor = "<green>", inside = false, textColor = "<purple>"}))
    cecho("<purple>Usage is:\n  Stygian_chaser([[lua code to execute]], {table of options})\n\nMinimum usage is Stygian_chaser([[send(\"command\")]]) which will send \"command\" to the mud, minus the quotes, when you have EQ and Balance, and expect it to consume both")
  end
  local options
  if type(code) ~= "string" then code = tostring(code) end --ensure the code they're sending is a string

--if they send a table as the second argument, copy it into our options. If they send anything else, or nothing at all, make options an empty table
  if type(optiontable) ~= "table" then options = {} else options = optiontable end 

--initialize all options to true, but only if the user hasn't specified false. (this way if they specify something other than false, like "banana", it'll default to true. This keeps my code from breaking later, and what the options are is pretty clearly laid out.
  if options.needsEq ~= false then options.needsEq = true end
  if options.needsBal ~= false then options.needsBal = true end
  if options.consumesEq ~= false then options.consumesEq = options.needsEq end --We can't consume EQ if we don't need EQ
  if options.consumesBal ~= false then options.consumesBal = options.needsBal end --Same for balance... if we're not requiring balance, we cannot consume
  
  
--a bunch of messy if/elseif logic to build the tables we'll be using (ok, not that messy, but ugly)
  if options.needsEq and options.needsBal then
    if options.consumesEq and options.consumesBal then
      table.insert(Stygian.NeedsEqAndBal.ConsumesEqAndBal, code)
    elseif options.consumesEq and not options.consumesBal then 
      table.insert(Stygian.NeedsEqAndBal.ConsumesEq, code)
    elseif not options.consumesEq and options.consumesBal then
      table.insert(Stygian.NeedsEqAndBal.ConsumesBal, code)
    elseif not options.consumesEq and not options.consumesBal then
      table.insert(Stygian.NeedsEqAndBal.ConsumesNeither, code)
    end
  elseif options.needsEq and not options.needsBal then
    if options.consumesEq then
      table.insert(Stygian.NeedsEq.ConsumesEq, code)
    else
      table.insert(Stygian.NeedsEq.ConsumesNothing, code)
    end
  elseif not options.needsEq and options.needsBal then
    if options.consumesBal then
      table.insert(Stygian.NeedsBal.ConsumesBal, code)
    else
      table.insert(Stygian.NeedsBal.ConsumesNothing, code)
    end
  end
end


--a function to do maintenance stuff for chasing EQ
function Stygian_chasingEq()
  SDebug("chaser", "Setting EQ Chasing for 0.5 seconds as a failsafe to prevent multi-command-entering")
  Stygian.chasingEq = true
  tempTimer(0.5, function () Stygian.chasingEq = false;Stygian.currentlyChasingEq = "";SDebug("chaser", "Unsetting EQ Chasing")end) 
end


--a function to do maintenance stuff for chasing BAL
function Stygian_chasingBal()
  SDebug("chaser", "Setting BAL chasing for 0.5 seconds as a failsafe to prevent multi-command-entering")
  Stygian.chasingBal = true
  tempTimer(0.5, function() Stygian.chasingBal = false ; Stygian.currentlyChasingBal = "";SDebug("chaser", "Unsetting Bal Chasing") end)
end


--the function to do the chasing! Should be fired by either the prompt, or by events for regaining Eq and Bal.
function Stygian_doChase()
  if Stygian.config.armbal then Stygian_armbalChase() end
--  if Stygian.writhing > 0 then return end
  if Stygian.balances.balance == 1 and Stygian.balances.equilibrium == 1 then  --we have both EQ and balance
    SDebug("chaser", "Ok, we're doing the chasing, and have both EQ and BAL")
    if #Stygian.NeedsEqAndBal.ConsumesNeither > 0 then --so do the things which need both but consume nothing
    SDebug("chaser", "Run through those things which require EQ and BAL but consume neither")
      for i=1,#Stygian.NeedsEqAndBal.ConsumesNeither do
        assert(loadstring(table.remove(Stygian.NeedsEqAndBal.ConsumesNeither,1))) ()
      end
    end
    if #Stygian.NeedsEq.ConsumesNothing > 0 then -- and the things which require only eq but consume nothing
    SDebug("chaser", "Run though those things which require EQ but do not consume it")
      for i=1,#Stygian.NeedsEq.ConsumesNothing do 
        assert(loadstring(table.remove(Stygian.NeedsEq.ConsumesNothing,1))) ()
      end
    end
    if #Stygian.NeedsBal.ConsumesNothing > 0 then -- and the things which require balance but consume nothing
    SDebug("chaser", "Run through those things which require BAL but do not consume it")
      for i=1, #Stygian.NeedsBal.ConsumesNothing do
        assert(loadstring(table.remove(Stygian.NeedsBal.ConsumesNothing,1))) ()
      end
    end
    if #Stygian.NeedsEqAndBal.ConsumesEqAndBal > 0 and not Stygian.chasingEq and not Stygian.chasingBal then -- then if we have anything which requires both and consumes both, do that.
      SDebug("chaser", "Do the first thing which requires both EQ and BAL and consumes both")
      Stygian.currentlyChasingEq = table.remove(Stygian.NeedsEqAndBal.ConsumesEqAndBal,1)
      Stygian.currentlyChasingBal = _G[Stygian[currentlyChasingEq]]
      Stygian_chasingBal()
      Stygian_chasingEq()
      assert(loadstring(Stygian.currentlyChasingEq)) ()
      return
    end
    if Stygian.config.ChaseEqFirst == true then --then, we check if we're configured to chase equilibrium before balance. If so
      SDebug("chaser", "We're chasing EQ before BAL")
      if #Stygian.NeedsEqAndBal.ConsumesEq > 0 and not Stygian.chasingEq and not Stygian.chasingBal then -- Check if we have something which requires Eq and Bal, but consumes only Eq. Use failsafe to be sure we're not in the process of trying to use up one or both
        SDebug("chaser", "Do that which requires EQ and BAL, but consumes only EQ")
        Stygian.currentlyChasingEq = table.remove(Stygian.NeedsEqAndBal.ConsumesEq,1)
        Stygian_chasingEq()
        assert(loadstring(Stygian.currentlyChasingEq)) ()
      end
      if #Stygian.NeedsEqAndBal.ConsumesBal > 0 and not Stygian.chasingEq and not Stygian.chasingBal then --then check if we have something which needs both eq and bal, but consumes only Bal. Same failsafe, so if the previous if fires off an action, this one won't eval true, even if we haven't lost EQ yet.
        SDebug("chaser", "Do that which requires EQ and BAL, but consumes only BAL")
        Stygian.currentlyChasingBal = table.remove(Stygian.NeedsEqAndBal.ConsumesBal,1)
        Stygian_chasingBal()
        assert(loadstring(Stygian.currentlyChasingBal)) ()
      end
      if #Stygian.NeedsEq.ConsumesEq > 0 and not Stygian.chasingEq then
        SDebug("chaser", "Do that which requires only EQ and consumes it")
        Stygian.currentlyChasingEq = table.remove(Stygian.NeedsEq.ConsumesEq,1)
        Stygian_chasingEq()
        assert(loadstring(Stygian.currentlyChasingEq)) ()
      end
      if #Stygian.NeedsBal.ConsumesBal > 0 and not Stygian.chasingBal then
        SDebug("chaser", "Do that which requires only BAL, and consumes it")
        Stygian.currentlyChasingBal = table.remove(Stygian.NeedsBal.ConsumesBal,1)
        Stygian_chasingBal()
        assert(loadstring(Stygian.currentlyChasingBal)) ()
      end
    else
      SDebug("chaser", "We're chasing BAL before EQ")
      if #Stygian.NeedsEqAndBal.ConsumesBal > 0 and not Stygian.chasingBal then
        SDebug("chaser", "Do that which requires EQ and BAL, but consumes only BAL")
        Stygian.currentlyChasingBal = table.remove(Stygian.NeedsEqAndBal.ConsumesBal,1)
        Stygian_chasingBal()
        assert(loadstring(Stygian.currentlyChasingBal)) ()
      end
      if #Stygian.NeedsEqAndBal.ConsumesEq > 0 and not Stygian.chasingEq then
        SDebug("chaser", "Do that which requires EQ and BAL, but consumes only EQ")
        Stygian.currentlyChasingEq = table.remove(Stygian.NeedsEqAndBal.ConsumesEq,1)
        Stygian_chasingEq()
        assert(loadstring(Stygian.currentlyChasingEq)) ()
      end
      if #Stygian.NeedsBal.ConsumesBal > 0 and not Stygian.chasingBal then
        Stygian.currentlyChasingBal = table.remove(Stygian.NeedsBal.ConsumesBal,1)
        SDebug("chaser", "Do that which requires only BAL, and consumes it")
        Stygian_chasingBal()
        assert(loadstring(Stygian.currentlyChasingBal)) ()
      end
      if #Stygian.NeedsEq.ConsumesEq > 0 and not Stygian.chasingEq then
        SDebug("chaser", "Do that which requires only EQ and consumes it")
        Stygian.currentlyChasingEq = table.remove(Stygian.NeedsEq.ConsumesEq,1)
        Stygian_chasingEq()
        assert(loadstring(Stygian.currentlyChasingEq)) ()
      end
    end
    return
  elseif Stygian.balances.balance < 1 and Stygian.balances.equilibrium == 1 then
    SDebug("chaser", "We have EQ but not Balance and " .. Stygian.balances.balance .. " is the value of the balance flag")
    if #Stygian.NeedsEq.ConsumesNothing > 0 then
      SDebug("chaser", "Do that which requires only EQ but does not consume it")
      for i=1,#Stygian.NeedsEq.ConsumesNothing do 
        assert(loadstring(table.remove(Stygian.NeedsEq.ConsumesNothing,1))) ()
      end
    end
    if #Stygian.NeedsEq.ConsumesEq > 0 and not Stygian.chasingEq then
      SDebug("chaser", "Do that which requires only EQ and consumes it")
      Stygian.currentlyChasingEq = table.remove(Stygian.NeedsEq.ConsumesEq,1)
      Stygian_chasingEq()
      assert(loadstring(Stygian.currentlyChasingEq)) ()
    end
    return
  elseif Stygian.balances.balance == 1 and Stygian.balances.equilibrium ~= 1 then 
    if #Stygian.NeedsBal.ConsumesNothing > 0 then
      SDebug("chaser", "Do that which requires only BAL but does not consume it")
      for i=1,#Stygian.NeedsBal.ConsumesNothing do
        assert(loadstring(table.remove(Stygian.needsEq.ConsumesNothing,1))) ()
      end
    end
    if #Stygian.NeedsBal.ConsumesBal > 0 and not Stygian.chasingBal then
      SDebug("chaser", "Do that which requires only BAL and consumes it")
      Stygian.currentlyChasingBal = table.remove(Stygian.NeedsBal.ConsumesBal,1)
      Stygian_chasingBal()
      assert(loadstring(Stygian.currentlyChasingBal)) ()
    end
    return
  else 
    return
  end      
end

function Stygian_complexBalance()
  if Stygian.balances.balance == 1 and Stygian.balances.leftArm == 1 and Stygian.balances.rightArm == 1 then return true else return false end
end

function Stygian_armbalChase()

end

